<template>
    <div class="f-uploader">
        <div @click="onClickUpload" ref="trigger">
            <slot></slot>
        </div>
        <slot name="tips"></slot>
        <ol class="f-uploader-fileList">
            <li v-for="file in fileList" :key="file.name">
                <template v-if="file.status === 'uploading'">
                    <f-icon name="loading" class="f-uploader-spin"></f-icon>
                </template>
                <template v-else-if="file.type.indexOf('image')===0">
                    <!-- TODO 失败 -->
                    <img class="f-uploader-image" :src="file.url" alt="" height="32" >
                </template>
                <template v-else>
                    <div class="f-uploader-defaultImage"></div>
                </template>

                <span class="f-uploader-name" :class="{[file.status]:file.status}">{{file.name}}</span>
                <button class="f-uploader-remove" @click="onRemoveFile(file)">x</button>
            </li>
        </ol>
        <div ref="temp" style="width:0;height:0;overflow:hidden;"></div>
    </div>
</template>

<script>
  import FIcon from './components/icon.vue';
  import http from './http';

  export default {
    name: "FUploader"
    ,components:{FIcon}
    ,props:{
      name:{type:String,required:true}
      ,action:{type:String,required:true}
      ,method:{type:String,default:'POST'}
      ,parseResponse:{type:Function,required:true}
      ,fileList:{type:Array,default:()=>[]}
      ,sizeLimit:{type:Number,default:1024*1024*2}
    }
    ,data(){
      return {
        url:'about:blank'
      }
    }
    ,methods:{
      onClickUpload(){
        let input = this.createInput();

        input.addEventListener('change', () => {
          // let file = input.files[0];
          this.uploadFiles(input.files);
          input.remove();
        });

        input.click();
      }
      /*,uploadFiles(files){
        let formData = new FormData();
        for (let i = 0; i < files.length; ++i) {
          formData.append(this.name, files[i]);
        }
        let xhr = new XMLHttpRequest();
        xhr.open(this.method, this.action);
        xhr.send(formData);
      }*/
      ,uploadFiles(files){
        let newNames = [];
        for(let i=0;i<files.length;++i){
          let file = files[i];
          let {name, size, type} = file;
          let newName = this.generateName(name);
          newNames[i] = newName;
        }

        if(!this.beforeUpdates(files,newNames)) return;

        for(let i=0;i<files.length;++i){
          let file = files[i];
          let newName = newNames[i];
          //事件是同步的，但组件渲染是异步的
          //父组件虽然能马上拿到新的fileList，但是子组件要在重新接受props(UI重新渲染时)时才会更新

          let formData = new FormData();
          formData.append(this.name,file);
          this.doUploadFile(formData,(response)=>{
            let url = this.parseResponse(response);
            this.url = url;
            this.afterUploadFile(newName,url); //  去掉菊花 && this.$emit('update:fileList', fileListCopy);
          },(xhr)=>{
            this.uploadError(xhr,newName)
          })
        }
      }
      ,beforeUpdate(file,newName){
        let {size, type} = file;
        if(size>this.sizeLimit){
          this.$emit('error', '文件大于2MB');
          return false;
        }else{
          // this.$emit('update:fileList',[...this.fileList,{name:newName,type,size,status:'uploading'}])
          //不要关心之前有什么，只关心新增
          this.$emit('addFile',{name: newName, type, size, status: 'uploading'});
          return true;
        }
      }
      //beforeUploadFiles
      ,beforeUpdates(files,newNames){
        files = Array.from(files);
        for(let i=0;i<files.length;++i){
          let {size, type} = files[i];
          if(size>this.sizeLimit){
            this.$emit('error', '文件大于2MB');
            return false;
          }
        }
        let x = files.map((file, i) => {
          let {type, size} = file;
          return {name: newNames[i], type, size, status: 'uploading'};
        });
        this.$emit('update:fileList',[...this.fileList,...x]);
        return true;
      }
      ,onRemoveFile(file){
        let answer = window.confirm('你确定要删除吗?');
        if(answer){
          let copy = [...this.fileList];
          let index = copy.indexOf(file);
          copy.splice(index, 1);
          this.$emit('update:fileList', copy);
        }
      }
      ,createInput(){
        // create input
        this.$refs.temp.innerHTML = ''; //防止确认时一直点击取消导致input堆叠
        let input = document.createElement('input');
        input.accept = "image/*"; //TODO 支持自定义
        input.type = 'file';
        input.multiple = true;
        this.$refs.temp.appendChild(input);
        return input;
      }
      ,afterUploadFile(newName,url){
        let x= this.fileList.filter(f => f.name === newName)[0];
        let copy = JSON.parse(JSON.stringify(x));
        copy.url = url;
        copy.status = 'success';
        let index = this.fileList.indexOf(x);
        let fileListCopy = [...this.fileList];
        fileListCopy.splice(index, 1, copy);
        this.$emit('update:fileList', fileListCopy);
        this.emit('uploaded');
      }
      ,uploadError(xhr,newName){
        let file = this.fileList.filter(f => f.name === newName)[0];
        let index = this.fileList.indexOf(file);
        let fileCopy = JSON.parse(JSON.stringify(file));
        fileCopy.status = 'fail';
        // fileCopy.failMessage = 'xxx';
        let fileListCopy = [...this.fileList];
        fileListCopy.splice(index, 1, fileCopy);
        this.$emit('update:fileList', fileListCopy);
        let error = '';
        if(xhr.status === 0){
          error='网络无法连接';
        }
        this.$emit('error',error);
      }
      ,generateName(name){
        while(this.fileList.filter(f=>f.name === name).length>0){
          let dotIndex = name.lastIndexOf('.');
          let nameWithoutExtension = name.substring(0, dotIndex);
          let extension = name.substring(dotIndex);
          name = nameWithoutExtension + '(1)' + extension;
        }
        return name;
      }
      ,doUploadFile(formData,success,fail){
        http[this.method.toLowerCase](this.action, {success, fail, data: formData});
      }
    }
  }
</script>

<style lang="scss">
    @import './components/var';
    .f-uploader{
        &-fileList{
            list-style:none;
            >li{
                display:flex;
                align-items:center;
                margin:8px 0;
                border:1px solid $grey;
            }
        }
        &-defaultImage{
            width: 32px;
            height: 32px;
            margin-right:8px;
        }
        &-imag{
            margin-right:8px;
        }
        &-name{
            margin-right:auto;
            &.success {
                color: green;
            }
            &.fail {
                color: red;

            }
        }
        &-remove{
            width: 32px;
            height: 32px;
        }
        &-spin {
            width: 32px;
            height: 32px;
            @include spin;
        }
    }
</style>
